home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / goodies / qtaddeffectseg.win / addeffectsegment.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  11.8 KB  |  406 lines

  1. //////////
  2. //
  3. //    File:        AddEffectSegment.c
  4. //
  5. //    Contains:    Sample code for adding a visual effect to a segment of a movie.
  6. //
  7. //    Written by:    Tim Monroe
  8. //
  9. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  10. //
  11. //    Change History (most recent first):
  12. //
  13. //       <2>         05/06/99    rtm        tested on Mac and Windows; works fine
  14. //       <1>         05/05/99    rtm        first file; some functions based on some existing code
  15. //                                    in QTShowEffect
  16. //       
  17. //    This file contains some sample code that adds a QuickTime effect to a part of a movie;
  18. //    we assume that the movie already exists and that it contains one or more video tracks.
  19. //    Our job here is to add a specified effect at a specified time. For one- or two-source
  20. //    effects, the principal value in this code consists in illustrating how to duplicate the
  21. //    portion(s) of the existing video track(s) for use as the effects source track(s).
  22. //
  23. //////////
  24.  
  25. #include "AddEffectSegment.h"
  26.  
  27.  
  28. //////////
  29. //
  30. // QTEffSeg_AddEffectToMovieSegment
  31. // Add the specified effect to occur at the specified time and duration.
  32. //
  33. //////////
  34.  
  35. OSErr QTEffSeg_AddEffectToMovieSegment (Movie theMovie, OSType theEffectType, long theNumSources, TimeValue theStartTime, TimeValue theDuration)
  36. {
  37.     Track                    myVidTrack1 = NULL;
  38.     Track                    myVidTrack2 = NULL;
  39.     Track                    mySrcTrack1 = NULL;
  40.     Track                    mySrcTrack2 = NULL;
  41.     Media                    mySrcMedia1 = NULL;
  42.     Media                    mySrcMedia2 = NULL;
  43.     Track                    myEffectTrack = NULL;
  44.     Media                    myEffectMedia = NULL;
  45.     Fixed                    myWidth, myHeight;
  46.     TimeScale                myTimeScale;
  47.     TimeValue                mySampleTime;
  48.     Rect                    myRect;
  49.     QTAtomContainer            myInputMap = NULL;
  50.     QTAtomContainer            myEffectDesc = NULL;
  51.     ImageDescriptionHandle    mySampleDesc = NULL;
  52.     OSType                    myEffectName1 = kSourceNoneName;
  53.     OSType                    myEffectName2 = kSourceNoneName;
  54.     short                    myLayer;
  55.     OSErr                    myErr = noErr;
  56.     
  57.     // make sure we were passed a valid movie
  58.     if (theMovie == NULL)
  59.         return(paramErr);
  60.         
  61.     //////////
  62.     //
  63.     // get some information about the movie
  64.     //
  65.     //////////
  66.     
  67.     myTimeScale = GetMovieTimeScale(theMovie);
  68.     GetMovieBox(theMovie, &myRect);
  69.     myLayer = QTEffSeg_GetFrontmostTrackLayer(theMovie, VideoMediaType);
  70.     
  71.     myWidth = (myRect.right - myRect.left) << 16;
  72.     myHeight = (myRect.bottom - myRect.top) << 16;
  73.  
  74.     //////////
  75.     //
  76.     // retrieve the original video track(s), create the effect's source track(s) and media,
  77.     // then set the new source track(s) to reference the data in the original video track(s)
  78.     //
  79.     //////////
  80.     
  81.     switch (theNumSources) {
  82.         case 2:
  83.             myVidTrack2 = GetMovieIndTrackType(theMovie, 2, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  84.             if (myVidTrack2 == NULL)
  85.                 return(paramErr);
  86.             
  87.             mySrcTrack2 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
  88.             if (mySrcTrack2 == NULL)
  89.                 return(paramErr);
  90.                 
  91.             mySrcMedia2 = NewTrackMedia(mySrcTrack2, VideoMediaType, myTimeScale, NULL, 0);
  92.             if (mySrcMedia2 == NULL)
  93.                 return(paramErr);
  94.             
  95.             myErr = CopyTrackSettings(myVidTrack2, mySrcTrack2);
  96.             myErr = InsertTrackSegment(myVidTrack2, mySrcTrack2, theStartTime, theDuration, theStartTime);
  97.             if (myErr != noErr)
  98.                 return(myErr);
  99.  
  100.             myEffectName2 = kSourceTwoName;
  101.             
  102.             // note that we fall through here!
  103.                 
  104.         case 1:
  105.             myVidTrack1 = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  106.             if (myVidTrack1 == NULL)
  107.                 return(paramErr);
  108.                 
  109.             mySrcTrack1 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume);
  110.             if (mySrcTrack1 == NULL)
  111.                 return(paramErr);
  112.                 
  113.             mySrcMedia1 = NewTrackMedia(mySrcTrack1, VideoMediaType, myTimeScale, NULL, 0);
  114.             if (mySrcMedia1 == NULL)
  115.                 return(paramErr);
  116.  
  117.             myErr = CopyTrackSettings(myVidTrack1, mySrcTrack1);
  118.             myErr = InsertTrackSegment(myVidTrack1, mySrcTrack1, theStartTime, theDuration, theStartTime);
  119.             if (myErr != noErr)
  120.                 return(myErr);
  121.             
  122.             myEffectName1 = kSourceOneName;
  123.             
  124.             break;
  125.             
  126.         case 0:
  127.             // for 0-source effects, we don't need to create any new source track
  128.             break;
  129.     
  130.         default:
  131.             return(paramErr);
  132.     }
  133.     
  134.     //////////
  135.     //
  136.     // create the effects track and media
  137.     //
  138.     //////////
  139.  
  140.     myEffectTrack = NewMovieTrack(theMovie, myWidth, myHeight, 0);
  141.     if (myEffectTrack == NULL)
  142.         return(paramErr);
  143.         
  144.     myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, myTimeScale, NULL, 0);
  145.     if (myEffectMedia == NULL)
  146.         return(paramErr);
  147.     
  148.     // create an effect sample description
  149.     mySampleDesc = QTEffSeg_MakeSampleDescription(theEffectType, myWidth >> 16, myHeight >> 16);
  150.     if (mySampleDesc == NULL)
  151.         goto bail;
  152.  
  153.     // create an effect description
  154.     myEffectDesc = QTEffSeg_CreateEffectDescription(theEffectType, myEffectName1, myEffectName2);
  155.  
  156.     // add the effect description as a sample to the effect track media
  157.     BeginMediaEdits(myEffectMedia);
  158.  
  159.     myErr = AddMediaSample(myEffectMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), theDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime);
  160.     if (myErr != noErr)
  161.         goto bail;
  162.  
  163.     EndMediaEdits(myEffectMedia);
  164.     
  165.     //////////
  166.     //
  167.     // create the input map and add references for the source track(s)
  168.     //
  169.     //////////
  170.  
  171.     myErr = QTNewAtomContainer(&myInputMap);
  172.     if (myErr != noErr)
  173.         goto bail;
  174.     
  175.     if (mySrcTrack1 != NULL) {    
  176.         myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack1, kSourceOneName);
  177.         if (myErr != noErr)
  178.             goto bail;
  179.     }
  180.         
  181.     if (mySrcTrack2 != NULL) {    
  182.         myErr = QTEffSeg_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack2, kSourceTwoName);
  183.         if (myErr != noErr)
  184.             goto bail;
  185.     }
  186.         
  187.     // add the input map to the effects track
  188.     myErr = SetMediaInputMap(myEffectMedia, myInputMap);
  189.     if (myErr != noErr)
  190.         goto bail;
  191.  
  192.     //////////
  193.     //
  194.     // add the media sample to the effects track
  195.     //
  196.     //////////
  197.  
  198.     myErr = InsertMediaIntoTrack(myEffectTrack, theStartTime, mySampleTime, theDuration, fixed1);
  199.     if (myErr != noErr)
  200.         goto bail;
  201.  
  202.     //////////
  203.     //
  204.     // do any required positioning and graphics mode manipulation
  205.     //
  206.     //////////
  207.  
  208.     SetTrackLayer(myEffectTrack, myLayer - 1);    // in front of any existing video track
  209.     
  210.     switch (theNumSources) {
  211.         case 2:
  212.             break;
  213.             
  214.         case 1:
  215.             break;
  216.             
  217.         case 0: {
  218.             RGBColor    myColor;
  219.             
  220.             myColor.red = 0;        // (good for fire, not so good for clouds)
  221.             myColor.green = 0;
  222.             myColor.blue = 0;
  223.             
  224.             MediaSetGraphicsMode(GetMediaHandler(myEffectMedia), transparent, &myColor);
  225.             break;
  226.         }
  227.     }
  228.     
  229. bail:
  230.     if (mySampleDesc != NULL)
  231.         DisposeHandle((Handle)mySampleDesc);
  232.     
  233.     if (myInputMap != NULL)
  234.         QTDisposeAtomContainer(myInputMap);
  235.     
  236.     return(myErr);
  237. }
  238.  
  239.  
  240. //////////
  241. //
  242. // QTEffSeg_CreateEffectDescription
  243. // Create an effect description for zero, one, or two sources.
  244. // 
  245. // The effect description specifies which video effect is desired and the parameters for that effect.
  246. // It also describes the source(s) for the effect. An effect description is simply an atom container
  247. // that holds atoms with the appropriate information.
  248. //
  249. // Note that because we are creating an atom container, we must pass big-endian data (hence the calls
  250. // to EndianU32_NtoB).
  251. //
  252. // The caller is responsible for disposing of the returned atom container, by calling QTDisposeAtomContainer.
  253. //
  254. //////////
  255.  
  256. QTAtomContainer QTEffSeg_CreateEffectDescription (OSType theEffectName, OSType theSourceName1, OSType theSourceName2)
  257. {
  258.     QTAtomContainer        myEffectDesc = NULL;
  259.     OSType                myType;
  260.     OSErr                myErr = noErr;
  261.  
  262.     // create a new, empty effect description
  263.     myErr = QTNewAtomContainer(&myEffectDesc);
  264.     if (myErr != noErr)
  265.         goto bail;
  266.  
  267.     // create the effect ID atom: the atom type is kParameterWhatName, and the atom ID is kParameterWhatID
  268.     myType = EndianU32_NtoB(theEffectName);
  269.     myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, 0, sizeof(myType), &myType, NULL);
  270.     if (myErr != noErr)
  271.         goto bail;
  272.         
  273.     // add the first source, if it's not kSourceNoneName
  274.     if (theSourceName1 != kSourceNoneName) {
  275.         myType = EndianU32_NtoB(theSourceName1);
  276.         myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myType), &myType, NULL);
  277.         if (myErr != noErr)
  278.             goto bail;
  279.     }
  280.                             
  281.     // add the second source, if it's not kSourceNoneName
  282.     if (theSourceName2 != kSourceNoneName) {
  283.         myType = EndianU32_NtoB(theSourceName2);
  284.         myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myType), &myType, NULL);
  285.     }
  286.  
  287. bail:
  288.     return(myEffectDesc);
  289. }
  290.  
  291.  
  292. //////////
  293. //
  294. // QTEffSeg_AddTrackReferenceToInputMap
  295. // Add a track reference to the specified input map.
  296. // 
  297. //////////
  298.  
  299. OSErr QTEffSeg_AddTrackReferenceToInputMap (QTAtomContainer theInputMap, Track theTrack, Track theSrcTrack, OSType theSrcName)
  300. {
  301.     OSErr                myErr = noErr;
  302.     QTAtom                myInputAtom;
  303.     long                myRefIndex;
  304.     OSType                myType;
  305.  
  306.     myErr = AddTrackReference(theTrack, theSrcTrack, kTrackModifierReference, &myRefIndex);
  307.     if (myErr != noErr)
  308.         goto bail;
  309.             
  310.     // add a reference atom to the input map
  311.     myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex, 0, 0, NULL, &myInputAtom);
  312.     if (myErr != noErr)
  313.         goto bail;
  314.     
  315.     // add two child atoms to the parent reference atom
  316.     myType = EndianU32_NtoB(kTrackModifierTypeImage);
  317.     myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myType), &myType, NULL);
  318.     if (myErr != noErr)
  319.         goto bail;
  320.     
  321.     myType = EndianU32_NtoB(theSrcName);
  322.     myErr = QTInsertChild(theInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myType), &myType, NULL);
  323.         
  324. bail:
  325.     return(myErr);
  326. }
  327.  
  328.  
  329. //////////
  330. //
  331. // QTEffSeg_MakeSampleDescription
  332. // Return a new image description with default and specified values.
  333. // 
  334. //////////
  335.  
  336. ImageDescriptionHandle QTEffSeg_MakeSampleDescription (OSType theEffectType, short theWidth, short theHeight)
  337. {
  338.     ImageDescriptionHandle        mySampleDesc = NULL;
  339.  
  340. #if USES_MAKE_IMAGE_DESC_FOR_EFFECT
  341.     OSErr                        myErr = noErr;
  342.     
  343.     // create a new sample description
  344.     myErr = MakeImageDescriptionForEffect(theEffectType, &mySampleDesc);
  345.     if (myErr != noErr)
  346.         return(NULL);
  347. #else
  348.     // create a new sample description
  349.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  350.     if (mySampleDesc == NULL)
  351.         return(NULL);
  352.         
  353.     // fill in the fields of the sample description
  354.     (**mySampleDesc).cType = theEffectType;
  355.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  356.     (**mySampleDesc).hRes = 72L << 16;
  357.     (**mySampleDesc).vRes = 72L << 16;
  358.     (**mySampleDesc).frameCount = 1;
  359.     (**mySampleDesc).depth = 0;
  360.     (**mySampleDesc).clutID = -1;
  361. #endif
  362.     
  363.     (**mySampleDesc).vendor = kAppleManufacturer;
  364.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  365.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  366.     (**mySampleDesc).width = theWidth;
  367.     (**mySampleDesc).height = theHeight;
  368.     
  369.     return(mySampleDesc);
  370. }
  371.  
  372.  
  373. //////////
  374. //
  375. // QTEffSeg_GetFrontmostTrackLayer
  376. // Return the layer number of the frontmost track of the specified kind in a movie.
  377. // 
  378. //////////
  379.  
  380. short QTEffSeg_GetFrontmostTrackLayer (Movie theMovie, OSType theTrackType)
  381. {
  382.     short        myLayer = 0;
  383.     short        myIndex = 1;
  384.     Track        myTrack = NULL;
  385.     
  386.     // get the layer number of the first track of the specified kind;
  387.     // if no track of that kind exists in the movie, return 0
  388.     myTrack = GetMovieIndTrackType(theMovie, 1, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
  389.     if (myTrack == NULL)
  390.         return(myLayer);
  391.         
  392.     myLayer = GetTrackLayer(myTrack);
  393.     
  394.     // see if any of the remaining tracks have lower layer numbers
  395.     while (myTrack != NULL) {
  396.         if (myLayer > GetTrackLayer(myTrack))
  397.             myLayer = GetTrackLayer(myTrack);
  398.         myIndex++;
  399.         myTrack = GetMovieIndTrackType(theMovie, myIndex, theTrackType, movieTrackMediaType | movieTrackEnabledOnly);
  400.     }
  401.     
  402.     return(myLayer);
  403. }
  404.  
  405.  
  406.